home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Utilities / Programming / EnterAct 3.5 / write your own Drag_on / CodeResource_Helper.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-22  |  23.6 KB  |  947 lines  |  [TEXT/KEEN]

  1. /* CodeResource_Helper.c - some handy functions for this and that */
  2. /* Copyright not bothered with - this is pretty standard stuff. */
  3. #include "CodeResource.h"
  4. #include <stdlib.h>
  5.  
  6. /* Resources */
  7. short OpenOrCreateResourceFork(StringPtr fileName);
  8. void DeleteAllExistingRsrcs(long theType, short theNum);
  9. /* Dialogs */
  10. void GetDlogOrigin (short dlogID, Point *where);
  11. Boolean GetAndAlignDialog(short  resID);
  12. void FrameDialogItem(DialogPtr theDP,short theItem);
  13. void SetEText(DialogPtr dPtr, short theItem, StringPtr newStr);
  14. void GetEText(DialogPtr dPtr, short theItem, StringPtr currentStr);
  15. void SetCheck(DialogPtr dPtr, short chkItem, short zeroMeansNoCheck);
  16. void GetCheck(DialogPtr dPtr, short chkItem, Boolean *trueIfChecked);
  17. Handle GetButton(DialogPtr dPtr, short btnItem);
  18. void HiliteDlgControl(DialogPtr dPtr, short btnItem, short state);
  19. /* Pascal strings */
  20. void CopyPStr(Byte *srcStr, Byte *dstStr);
  21. void AppendPStr(Byte *s1, Byte *s2);
  22. Boolean PEqualStrs(Byte *aStr, Byte *bStr);
  23. /* Files, names and locations */
  24. Byte *FullPathNameFromDirectory(long DirID, short vRefNum, Byte *s);
  25. Byte *FullPathNameFromVRefNum(short vRefNum, Byte *s);
  26. short    OpenWorkingDirectoryFromFullName(char *name, short len);
  27. /* Memory allocation */
  28. void InitTempCodeMemory(void);
  29. void *TMalloc(size_t size);
  30. void *Trealloc(void *ptr, size_t size);
  31. void Tfree(void *ptr);
  32. void TFreeAll(void);
  33. /* more memory allocation - faster, more efficient version */
  34. void *Fmalloc(register size_t nbytes);
  35. static void morecore(register short bucket);
  36. static void *true_get_memory(size_t size);
  37. void Ffree(void *cp);
  38. void *Frealloc(void *cp, size_t nbytes);
  39. static short findbucket(union overhead *freep, short srchlen);
  40. void FFreeAll(void);
  41. /* Misc */
  42. void NullOut(char *str, long nBytes);
  43. Boolean TaskWasInterrupted(void);
  44. Boolean CheckInWithCallingApp(void);
  45.  
  46. /* Resources */
  47.  
  48. /* Returns nonzero refnum if successful */
  49. short OpenOrCreateResourceFork(StringPtr fileName)
  50.     {
  51.     short refNum;
  52.     
  53.     if ((refNum = OpenResFile(fileName)) != -1 && refNum
  54.         && ResError() == noErr) /* perfect paranoia */
  55.         return(refNum);
  56.     else
  57.         {
  58.         CreateResFile(fileName);
  59.         if (ResError() != noErr)
  60.             return(0);
  61.         if ((refNum = OpenResFile(fileName)) != -1 && refNum
  62.             && ResError() == noErr)
  63.             return(refNum);
  64.         }
  65.     return(0);
  66.     }
  67.  
  68. /* Delete all instances of a particular resource.
  69. Call before creating each resource. */
  70. void DeleteAllExistingRsrcs(long theType, short theNum)
  71.     {
  72.     Handle        rsrcHdle;
  73.     
  74.     while (rsrcHdle = Get1Resource(theType, theNum))
  75.         {
  76.         RmveResource(rsrcHdle);
  77.         DisposHandle(rsrcHdle);
  78.         }
  79.     }
  80.  
  81.  
  82. /* Dialogs */
  83.  
  84. void GetDlogOrigin (short dlogID, Point *where)
  85.     {
  86.     short     screenWidth = GetScreenWidth();
  87.     short     screenHeight = GetScreenHeight();
  88.     register DialogTHndl dlogHandle;
  89.     register Rect * drp;
  90.     register short     dlogWidth, dlogHeight;
  91.  
  92.     /* Get a handle to the dialog */
  93.     dlogHandle = (DialogTHndl) GetResource ('DLOG', dlogID);
  94.  
  95.     if (!dlogHandle)
  96.         {
  97.         SetPt (where, 85, 85);
  98.         return;
  99.         }
  100.  
  101.     /* get pointer to its bounding rectangle */
  102.     drp = &((**dlogHandle).boundsRect);
  103.  
  104.     dlogWidth = drp->right - drp->left;
  105.     dlogHeight = drp->bottom - drp->top;
  106.  
  107.     /* Calculate upper left corner that will leave box centered */
  108.     where->h = (screenWidth - dlogWidth) >> 1;
  109.     where->v = (screenHeight - dlogHeight) >> 1;
  110.     }
  111.  
  112.  
  113. Boolean GetAndAlignDialog(short  resID)
  114.     {
  115.     short            sW,sH,dW,dH,left;
  116.     Rect        *drp;
  117.     DialogTHndl    dlogHandle;
  118.     Boolean        bigScreen;
  119.     
  120.     if (!GetResource('DLOG', resID)
  121.         || !GetResource('DITL', resID)
  122.         || ResError())
  123.         {
  124.         MemoryAlert();
  125.         return(FALSE);
  126.         }
  127.     sW = GetScreenWidth();
  128.     sH = GetScreenHeight();
  129.     dlogHandle = (DialogTHndl) GetResource('DLOG', resID);
  130.     drp = &((**dlogHandle).boundsRect);
  131.     dW = drp->right - drp->left;
  132.     dH = drp->bottom - drp->top;
  133.     left = (sW - dW)>>1;
  134.     /* all dialogs centered left-right */
  135.     drp->left = left;
  136.     drp->right = left + dW;
  137.     /* vertical placement depends on screen size */
  138.     if (sW >= 640 && sH >= 480)
  139.         bigScreen = TRUE;
  140.     else
  141.         bigScreen = FALSE;
  142.     
  143.     if (bigScreen)
  144.         {
  145.         /* leave one-third of white at top */
  146.         drp->top = (sH - dH) / 3;
  147.         if (drp->top < 85)
  148.             {
  149.             if (drp->top < 40)
  150.                 drp->top = 40;
  151.             if (sH <= 85 + dH)
  152.                 drp->top = 85;
  153.             }
  154.         }
  155.     else if (sH <= 85 + dH)
  156.         drp->top = 85;
  157.     else
  158.         drp->top = 40;
  159.     drp->bottom = drp->top + dH;
  160.     return(TRUE);
  161.     }
  162.  
  163. /* Place thick border around default item in a dialog */
  164. void FrameDialogItem(DialogPtr dPtr,short theItem)
  165.     {
  166.     GrafPtr            savePort;
  167.     PenState        savePen;
  168.     Handle           h;
  169.     Rect            theBox;
  170.     short                theType, ovalSize;
  171.  
  172.     GetDItem(dPtr,theItem,&theType,&h,&theBox);
  173.     GetPort(&savePort);
  174.     SetPort(dPtr);
  175.     GetPenState(&savePen);
  176.     PenNormal();
  177.     PenSize(2,2);
  178.     InsetRect(&theBox,-3,-3);
  179.     ovalSize = (theBox.bottom + 8 - theBox.top) / 2;    
  180.     FrameRoundRect(&theBox,ovalSize,ovalSize);
  181.     SetPenState(&savePen);
  182.     SetPort(savePort);
  183.     }
  184.  
  185. /* Set text content in a dialog edit field */
  186. void SetEText(DialogPtr dPtr, short theItem, StringPtr newStr)
  187.     {
  188.     short     theType;
  189.     Handle     theItemH;
  190.     Rect     theBox;
  191.  
  192.     GetDItem(dPtr, theItem, &theType, &theItemH, &theBox);
  193.     SetIText(theItemH, newStr);
  194.     }
  195.  
  196. /* Get current text in edit field - note storage for the string must
  197. be allocated by the calling function. */
  198. void GetEText(DialogPtr dPtr, short theItem, StringPtr currentStr)
  199.     {
  200.     short     theType;
  201.     Handle     theItemH;
  202.     Rect     theBox;
  203.  
  204.     GetDItem(dPtr, theItem, &theType, &theItemH, &theBox);
  205.     GetIText(theItemH, currentStr);
  206.     }
  207.  
  208. /* Set/clear check for check box or radio button, pass 0/1 or TRUE/FALSE . */
  209. void SetCheck(DialogPtr dPtr, short chkItem, short zeroMeansNoCheck)
  210.     {
  211.     short     theType;
  212.     Handle     theItemH;
  213.     Rect     theBox;
  214.  
  215.     GetDItem(dPtr, chkItem, &theType, &theItemH, &theBox);
  216.     SetCtlValue((ControlHandle)theItemH, zeroMeansNoCheck);
  217.     }
  218.  
  219. /* For check boxes and radio buttons, requires address of a Boolean from 
  220. the call as in GetCheck(dPtr, 3, &myBoolean). */
  221. /* Usage tip, to toggle a box do
  222. GetCheck (dPtr, chkItem, &myBoolean);
  223. SetCheck (dPtr, chkItem, !myBoolean);
  224. */
  225. void GetCheck(DialogPtr dPtr, short chkItem, Boolean *trueIfChecked)
  226.     {
  227.     short     theType;
  228.     Handle     theItemH;
  229.     Rect     theBox;
  230.  
  231.     GetDItem(dPtr, chkItem, &theType, &theItemH, &theBox);
  232.     *trueIfChecked = (GetCtlValue((ControlHandle)theItemH) != 0);
  233.     }
  234.  
  235. /* Retrieve ControlHandle for button, in the form of a Handle */
  236. Handle GetButton(DialogPtr dPtr, short btnItem)
  237.     {
  238.     short     theType;
  239.     Handle     theItem;
  240.     Rect     theBox;
  241.  
  242.     GetDItem(dPtr, btnItem, &theType, &theItem, &theBox);
  243.     return(theItem);
  244.     }
  245.  
  246. /* Enable (state 0) or disable (state 255) a dialog control */
  247. void HiliteDlgControl(DialogPtr dPtr, short btnItem, short state)
  248.     {
  249.     ControlHandle theButton;
  250.     
  251.     theButton = (ControlHandle) GetButton(dPtr, btnItem);
  252.     if ((**theButton).contrlHilite != state)
  253.         HiliteControl (theButton, state);
  254.     }
  255.  
  256. /* Pascal strings */
  257.  
  258. /* Copy one pascal string to another */
  259. void CopyPStr(Byte *srcStr, Byte *dstStr)
  260.     {
  261.     long   srcLen = srcStr[0];
  262.  
  263.     BlockMove(srcStr, dstStr, srcLen + 1);
  264.     }
  265.  
  266. /* Append pascal s2 to pascal s1, avoiding overflow. */
  267. void AppendPStr(Byte *s1, Byte *s2)
  268.     {
  269.     short    s1Len = s1[0];
  270.     short    s2Len = s2[0];
  271.  
  272.     if (s1Len + s2Len > 255)
  273.         s2Len = 255 - s1Len;
  274.  
  275.     if (s2Len)
  276.         {
  277.         BlockMove (s2 + 1, s1 + s1Len + 1, s2Len);
  278.         s1Len += s2Len;
  279.         s1[0] = s1Len;
  280.         }
  281.     }
  282.  
  283. Boolean PEqualStrs(Byte *aStr, Byte *bStr)
  284.     {
  285.     short i, lena = aStr[0], lenb = bStr[0];
  286.     
  287.     if (!lena || !lenb || lena != lenb)return(FALSE);
  288.     for (i = 1; i <= lena; ++i)
  289.         {
  290.         if (aStr[i] != bStr[i])
  291.             return(FALSE);
  292.         }
  293.     return(TRUE);
  294.     }
  295.  
  296. /* Files, names and locations */
  297.  
  298. /* NOTE the following two functions are based on examples supplied
  299. by Apple on one of their DTS disks - error checking has been added,
  300. and these versions are independent of the signed vs unsigned char
  301. controversy surrounding str255. Byte is defined in MacTypes.h
  302. for THINK C v4. */
  303.  
  304. /* Warning, these calls can fail! And why not? Everything else can... */
  305. /* Bug, these two are not for use by unix imitations. */
  306.  
  307. /* Construct "\PDisk:folder1:folder2:...folderN:" where folderN
  308. contains the file of interest. */
  309. Byte *FullPathNameFromDirectory(long DirID, short vRefNum, Byte *s)
  310.     {
  311.     CInfoPBRec    pb;
  312.     Byte        directoryName[256];
  313.  
  314.     s[0] = 0;
  315.     pb.dirInfo.ioNamePtr = (StringPtr)directoryName;
  316.     pb.dirInfo.ioDrParID = DirID;
  317.  
  318.     do 
  319.         {
  320.         pb.dirInfo.ioVRefNum = vRefNum;
  321.         pb.dirInfo.ioFDirIndex = -1;
  322.         pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
  323.         if (PBGetCatInfo(&pb, FALSE))
  324.             {
  325.             break;
  326.             }
  327.         /* Append a colon  */
  328.         AppendPStr(directoryName, (Byte *)"\p:");
  329.         AppendPStr(directoryName, s);
  330.         CopyPStr(directoryName, s);
  331.         } while (pb.dirInfo.ioDrDirID != 2);
  332.     return(s);
  333.     }
  334.  
  335.  
  336. Byte *FullPathNameFromVRefNum(short vRefNum, Byte *s)
  337.     {
  338.  
  339.     WDPBRec    pb;
  340.  
  341.     pb.ioNamePtr = NULL;
  342.     pb.ioVRefNum = vRefNum;
  343.     pb.ioWDIndex = 0;
  344.     pb.ioWDProcID = 0;
  345.  
  346.     if (PBGetWDInfo(&pb,false))
  347.         {
  348.         s[0] = 0;
  349.         return(s);
  350.         }
  351.     return(FullPathNameFromDirectory(pb.ioWDDirID,pb.ioWDVRefNum,s));
  352.     }
  353.  
  354. /* Determine working directory for file based on full path name. */
  355. short    OpenWorkingDirectoryFromFullName(char *name, short len)
  356.     {
  357.     WDPBRec        theParms;
  358.     OSErr     IOResult;
  359.     char volname[256];
  360.     extern void FileError(OSErr theFileErrorNum);
  361.     
  362.     volname[0] = len;
  363.     BlockMove(name, volname+1, len);
  364.     
  365.     theParms.ioCompletion = NULL;
  366.     theParms.ioVRefNum = 0;
  367.     theParms.ioNamePtr = (StringPtr)volname;
  368.     theParms.ioWDDirID = 2;
  369.     theParms.ioWDProcID = 'ERIK';
  370.     if (IOResult = PBOpenWD(&theParms, FALSE)) /* IM IV pg 158 */
  371.         {
  372.         OKStopAlert("Disk may not be on-line, \
  373. or file may have been moved, deleted, or renamed.");
  374.         theParms.ioVRefNum = 0;
  375.         }
  376.     return(theParms.ioVRefNum);
  377.     }
  378.  
  379.  
  380. /* Memory allocation */
  381. /* Preamble: at present, code resources fall into two camps; those
  382. that allocate a few chunks of memory via NewHandle, and those that
  383. allocate many chunks of memory via malloc. For the latter type,
  384. the following functions keep track of what memory was allocated,
  385. allowing it to be all freed at the end of a run with one call
  386. to TFreeAll().
  387.  
  388. To use the functions TMalloc etc  below instead of the standard malloc etc,
  389. place these lines in some header which is included in all your
  390. code resource files (see eg AWK.H), or at the top of each file:
  391.  
  392. extern void *TMalloc(size_t size);
  393. extern void *Trealloc(void *ptr, size_t size);
  394. extern void Tfree(void *ptr);
  395.  
  396. #define malloc(x) TMalloc(x)
  397. #define realloc(x, y) Trealloc(x, y)
  398. #define free(x) Tfree(x)
  399.  
  400. - before firing up your code resource, call InitTempCodeMemory()
  401.     - see eg InvokeHAWK() in hAWK_Interface.c
  402. -- and after your code resource is done, call TFreeAll()
  403.     - see eg CleanUpAfterHAWK() in hAWK_Interface.c
  404. NOTE InitTempCodeMemory() is called whether using TMalloc() etc
  405. or Fmalloc() etc, BUT the FreeAll() functions are different
  406. -TFreeAll() for the former, FFreeAll() for the latter.
  407. */
  408.  
  409.  
  410. #ifdef malloc
  411. #undef malloc
  412. #undef realloc
  413. #undef free
  414. #endif malloc
  415.  
  416. typedef struct MemoryLinks
  417.     {
  418.     struct MemoryLinks *next, *prev;
  419.     }MemoryLinks;
  420.  
  421. MemoryLinks    THead;
  422. MemoryLinks *THeadPtr /* = {&THead, NULL}*/;
  423.  
  424. void InitTempCodeMemory(void)
  425.     {
  426.     THeadPtr = &THead;
  427.     THeadPtr->next = &THead;
  428.     THeadPtr->prev = &THead;
  429.     }
  430.  
  431. /* Tracking versions of malloc, realloc, free - the T stands for temp */
  432. void *TMalloc(size_t size)
  433.     {
  434.     MemoryLinks *new, *old;
  435.     
  436.     size += sizeof(MemoryLinks);
  437.     if (!(new = (MemoryLinks *)malloc(size)))
  438.         return(NULL);
  439.     old = THeadPtr->next; /* true next or THead itself */
  440.     old->prev = new;
  441.     new->next = old;
  442.     new->prev = THeadPtr;
  443.     THeadPtr->next = new;
  444.     return((void *)(new + 1)); /* user doesn't "see" the links */
  445.     }
  446.  
  447. void *Trealloc(void *ptr, size_t size)
  448.     {
  449.     MemoryLinks *retPtr;
  450.     
  451.     if (!ptr)
  452.         return(TMalloc(size));
  453.     if (!size)
  454.         {
  455.         Tfree(ptr);
  456.         return(NULL);
  457.         }
  458.     retPtr = ((MemoryLinks *)(ptr)) - 1;
  459.     /* allocate MemoryLinks, too */
  460.     size += sizeof(MemoryLinks);
  461.     retPtr = (MemoryLinks *)realloc(retPtr, size);
  462.     if (!retPtr) /* failure, but block is still there */
  463.         return(NULL);
  464.     (retPtr->prev)->next = (retPtr->next)->prev = retPtr;
  465.     return((void *)(retPtr + 1));
  466.     }
  467.  
  468. void Tfree(void *ptr)
  469.     {
  470.     MemoryLinks *out;
  471.     
  472.     if (!ptr) return;
  473.     out = ((MemoryLinks *)(ptr)) - 1;
  474.     (out->next)->prev = out->prev;
  475.     (out->prev)->next = out->next;
  476.     free(out);
  477.     }
  478.  
  479. /* list wraps around */
  480. void TFreeAll(void)
  481.     {
  482.     MemoryLinks *dump = THeadPtr->next, *nextOne;
  483. #ifdef TMEMDEBUG
  484.     long    diff;
  485.     char    numStr[16];
  486. #endif
  487.     
  488.     while (dump != THeadPtr)
  489.         {
  490.         nextOne = dump->next;
  491.         free(dump);
  492.         dump = nextOne;
  493.         }
  494. #ifdef TMEMDEBUG
  495.     NumToString(malled, (StringPtr)numStr);
  496.     PtoCstr(numStr);
  497.     OKStopAlert("Total malloc'd:");
  498.     OKStopAlert(numStr);
  499.     NumToString(realled, (StringPtr)numStr);
  500.     PtoCstr(numStr);
  501.     OKStopAlert("Total realloc'd:");
  502.     OKStopAlert(numStr);
  503.  
  504.     if (numfreedAtEnd + tfreeNum != tmallocNum)
  505.         {
  506.         diff = numfreedAtEnd + tfreeNum - tmallocNum;
  507.         if (diff < 0L)
  508.             {
  509.             diff = -diff;
  510.             NumToString(diff, (StringPtr)numStr);
  511.             PtoCstr(numStr);
  512.             OKStopAlert(numStr);
  513.             }
  514.         else /* very odd - more freed than allocated */
  515.             {
  516.             NumToString(diff, (StringPtr)numStr);
  517.             PtoCstr(numStr);
  518.             SysBeep(2);
  519.             SysBeep(2);
  520.             OKStopAlert(numStr);
  521.             }
  522.         
  523.         }
  524.     else
  525.         {
  526.         NumToString(tmallocNum, (StringPtr)numStr);
  527.         PtoCstr(numStr);
  528.         OKStopAlert("Num malloc calls total:");
  529.         OKStopAlert(numStr);
  530.         }
  531. #endif
  532.     }
  533.  
  534. /* more memory allocation - a more efficient (frugal) version */
  535.  
  536. /* A frugal malloc, especially suited for allocating many many
  537. small blocks of memory. Currently used by hAWK, which is 
  538. constantly allocating and freeing small blocks. Note TMalloc()
  539. above basically uses THINK C's malloc, which suffers from
  540. severe fragmentation problems. There is also more overhead with
  541. TMalloc (8 bytes vs 4 here).
  542. Memory is pre–allocated on demand for specific sizes only which
  543. are all powers of two (plus overhead). When you request a block
  544. of memory, your requested size is rounded up to the next power
  545. of two, and the request is satisfied from an array of similar-
  546. sized blocks. */
  547.  
  548. /* Modified for the Mac and THINK C by Ken Earle.
  549.    Based on Larry Wall’s modification (1989) of:
  550.  * malloc.c (Caltech) 2/21/82
  551.  * Chris Kingsley, kingsley@cit-20.
  552.  *
  553.  * This is a very fast storage allocator.  It allocates blocks of a small
  554.  * number of different sizes, and keeps free lists of each size.  Blocks that
  555.  * don't exactly fit are passed up to the next larger size.  In this
  556.  * implementation, the available sizes are 2^n-4 bytes long.
  557.  * This is designed for use in a program that uses vast quantities of memory,
  558.  * but bombs when it runs out.
  559.  
  560. To use the functions Fmalloc etc  below instead of the standard malloc etc,
  561. place these lines in some header which is included in all your
  562. code resource files (see eg AWK.H and CodeResHelper.h), or at 
  563. the top of each file:
  564.  
  565. extern void *Fmalloc(size_t size);
  566. extern void *Frealloc(void *ptr, size_t size);
  567. extern void Ffree(void *ptr);
  568.  
  569. #define malloc(x) Fmalloc(x)
  570. #define realloc(x, y) Frealloc(x, y)
  571. #define free(x) Ffree(x)
  572.  
  573. - before firing up your code resource, call InitTempCodeMemory()
  574.     - see eg InvokeHAWK() in hAWK_Interface.c
  575. -- and after your code resource is done, call FFreeAll()
  576.     - see eg CleanUpAfterHAWK() in hAWK_Interface.c
  577. NOTE InitTempCodeMemory() is called whether using TMalloc() etc
  578. or Fmalloc() etc, BUT the FreeAll() functions are different
  579. -TFreeAll() for the former, FFreeAll() for the latter.
  580.  */
  581.  
  582. #define u_char unsigned char
  583. #define u_int unsigned short
  584. #define u_short unsigned short
  585.  
  586. /*
  587.  * The overhead on a block is at least 4 bytes.  When free, this space
  588.  * contains a pointer to the next free block, and the bottom two bits must
  589.  * be zero.  When in use, the first byte is set to MAGIC, and the second
  590.  * byte is the size index.  The remaining bytes are for alignment.
  591.  */
  592. union    overhead {
  593.     union    overhead *ov_next;    /* when free */
  594.     struct {
  595.         u_char    ovu_magic;    /* magic number */
  596.         u_char    ovu_index;    /* bucket # */
  597.     } ovu;
  598. };
  599. #define    ov_magic    ovu.ovu_magic
  600. #define    ov_index    ovu.ovu_index
  601.  
  602. #define    MAGIC        0xff        /* magic # on accounting info */
  603.  
  604. /*
  605.  * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
  606.  * smallest allocatable block is 8 bytes.  The overhead information
  607.  * precedes the data area returned to the user.
  608.  */
  609. #define    NBUCKETS 30
  610. static    union overhead *nextf[NBUCKETS];
  611.  
  612. #ifdef MSTATS
  613. /*
  614.  * nmalloc[i] is the difference between the number of mallocs and frees
  615.  * for a given block size.
  616.  */
  617. static    u_int nmalloc[NBUCKETS];
  618. #endif
  619.  
  620. /* F stands for Frugal */
  621. void *Fmalloc(register size_t nbytes)
  622.     {
  623.     register union overhead *p;
  624.     register short bucket = 0;
  625.     register size_t shiftr;
  626.     
  627.     /*
  628.      * Convert amount of memory requested into
  629.      * closest block size stored in hash buckets
  630.      * which satisfies request.  Account for
  631.      * space used per block for accounting.
  632.      */
  633.     nbytes += sizeof (union overhead);
  634.     nbytes = (nbytes + 3) &~ 3;
  635.     shiftr = (nbytes - 1) >> 2;
  636.     /* apart from this loop, this is O(1) */
  637.     while (shiftr >>= 1)
  638.         bucket++;
  639.     /*
  640.      * If nothing in hash bucket right now,
  641.      * request more memory from the system.
  642.      */
  643.     if (nextf[bucket] == NULL)
  644.         morecore(bucket);
  645.     if ((p = (union overhead *)nextf[bucket]) == NULL)
  646.         return (NULL);
  647.     /* remove from linked list */
  648.     nextf[bucket] = p->ov_next;
  649.     p->ov_magic = MAGIC;
  650.     p->ov_index = bucket;
  651. #ifdef MSTATS
  652.     nmalloc[bucket]++;
  653. #endif
  654.     return ((void *)(p + 1));
  655.     }
  656.  
  657. /*
  658.  * Allocate more memory to the indicated bucket.
  659.  */
  660. static void morecore(register short bucket)
  661.     {
  662.     register union overhead *op;
  663.     register short rnu;       /* 2^rnu bytes will be requested */
  664.     register short nblks;     /* become nblks blocks of the desired size */
  665.     register short siz;
  666.  
  667.     if (nextf[bucket])
  668.         return;
  669.     /* take 16k unless the block is bigger than that */
  670.     rnu = (bucket <= 11) ? 14 : bucket + 3;
  671.     
  672.     nblks = 1 << (rnu - (bucket + 3));  /* how many blocks to get */
  673.     if (rnu < bucket)
  674.         rnu = bucket;
  675.     op = (union overhead *)true_get_memory((size_t)(1 << rnu));
  676.     /* no more room! */
  677.     if (op == NULL)
  678.         return;
  679.     /*
  680.      * Add new memory allocated to that on
  681.      * free list for this hash bucket.
  682.      */
  683.     nextf[bucket] = op;
  684.     siz = 1 << (bucket + 3);
  685.     while (--nblks > 0) {
  686.         op->ov_next = (union overhead *)((char *)op + siz);
  687.         op = (union overhead *)((char *)op + siz);
  688.     }
  689.     op->ov_next = NULL;
  690. }
  691.  
  692. /* Allocate a large lump of memory, and remember it in a linked
  693. list so that it can be disposed later. */
  694. static void *true_get_memory(size_t size)
  695.     {
  696.     MemoryLinks *new, *old;
  697.     
  698.     size += sizeof(MemoryLinks);
  699.     if (!(new = (MemoryLinks *)NewPtr((long)size)))
  700.         return(NULL);
  701.     old = THeadPtr->next; /* true next or THead itself */
  702.     old->prev = new;
  703.     new->next = old;
  704.     new->prev = THeadPtr;
  705.     THeadPtr->next = new;
  706.     return((void *)(new + 1)); /* user doesn't "see" the links */
  707.     }
  708.  
  709. void Ffree(void *cp)
  710.     {
  711.     register short size;
  712.     register union overhead *op;
  713.     
  714.     if (cp == NULL)
  715.         return;
  716.     op = (union overhead *)((char *)cp - sizeof (union overhead));
  717.     if (op->ov_magic != MAGIC) {
  718.         return;                /* sanity */
  719.     }
  720.     size = op->ov_index;
  721.     op->ov_next = nextf[size];
  722.     nextf[size] = op;
  723. #ifdef MSTATS
  724.     nmalloc[size]--;
  725. #endif
  726.     }
  727.  
  728. /*
  729.  * When a program attempts "storage compaction" as mentioned in the
  730.  * old malloc man page, it realloc's an already freed block.  Usually
  731.  * this is the last block it freed; occasionally it might be farther
  732.  * back.  We have to search all the free lists for the block in order
  733.  * to determine its bucket: 1st we make one pass thru the lists
  734.  * checking only the first block in each; if that fails we search
  735.  * ``reall_srchlen'' blocks in each list for a match (the variable
  736.  * is extern so the caller can modify it).  If that fails we just copy
  737.  * however many bytes was given to realloc() and hope it's not huge.
  738.  */
  739. short reall_srchlen = 4;    /* 4 should be plenty, -1 =>'s whole list */
  740.  
  741. void *Frealloc(void *cp, size_t nbytes)
  742.     {
  743.     register size_t onb;
  744.     union overhead *op;
  745.     char *res;
  746.     register short i;
  747.     short was_alloced = 0;
  748.  
  749.     if (cp == NULL)
  750.         return (Fmalloc(nbytes));
  751.     if (!nbytes)
  752.         {
  753.         Ffree(cp);
  754.         return(NULL);
  755.         }
  756.     op = (union overhead *)((char *)cp - sizeof (union overhead));
  757.     if (op->ov_magic == MAGIC) {
  758.         was_alloced++;
  759.         i = op->ov_index;
  760.     } else {
  761.         /*
  762.          * Already free, doing "compaction".
  763.          *
  764.          * Search for the old block of memory on the
  765.          * free list.  First, check the most common
  766.          * case (last element free'd), then (this failing)
  767.          * the last ``reall_srchlen'' items free'd.
  768.          * If all lookups fail, then assume the size of
  769.          * the memory block being realloc'd is the
  770.          * smallest possible.
  771.          */
  772.         if ((i = findbucket(op, 1)) < 0 &&
  773.             (i = findbucket(op, reall_srchlen)) < 0)
  774.             i = 0;
  775.     }
  776.     onb = (1 << (i + 3)) - sizeof (*op);
  777.     /* avoid the copy if same size block */
  778.     if (was_alloced &&
  779.         nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op)) {
  780.         return(cp);
  781.     }
  782.     if ((res = Fmalloc(nbytes)) == NULL)
  783.         return (NULL);
  784.     if (cp != res)            /* common optimization */
  785.         BlockMove ((Ptr)cp, (Ptr)res, (Size)((nbytes < onb) ? nbytes : onb));
  786.     if (was_alloced)
  787.         Ffree(cp);
  788.     return (res);
  789. }
  790.  
  791. /*
  792.  * Search ``srchlen'' elements of each free list for a block whose
  793.  * header starts at ``freep''.  If srchlen is -1 search the whole list.
  794.  * Return bucket number, or -1 if not found.
  795.  */
  796. static short findbucket(union overhead *freep, short srchlen)
  797.     {
  798.     register union overhead *p;
  799.     register short i, j;
  800.  
  801.     for (i = 0; i < NBUCKETS; i++) {
  802.         j = 0;
  803.         for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
  804.             if (p == freep)
  805.                 return (i);
  806.             j++;
  807.         }
  808.     }
  809.     return (-1);
  810.     }
  811.  
  812. #ifdef MSTATS
  813. /*
  814.  * mstats - print out statistics about malloc
  815.  *
  816.  * Prints two lines of numbers, one showing the length of the free list
  817.  * for each size category, the second showing the number of mallocs -
  818.  * frees for each size category.
  819.  */
  820. void mstats(char *s);
  821. void mstats(char *s)
  822.     {
  823.     register short i, j;
  824.     register union overhead *p;
  825.     short totfree = 0,
  826.     totused = 0;
  827.  
  828.     fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
  829.     for (i = 0; i < NBUCKETS; i++) {
  830.         for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
  831.             ;
  832.         fprintf(stderr, " %d", j);
  833.         totfree += j * (1 << (i + 3));
  834.     }
  835.     fprintf(stderr, "\nused:\t");
  836.     for (i = 0; i < NBUCKETS; i++) {
  837.         fprintf(stderr, " %d", nmalloc[i]);
  838.         totused += nmalloc[i] * (1 << (i + 3));
  839.     }
  840.     fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
  841.         totused, totfree);
  842.     }
  843. #endif
  844.  
  845. /* list wraps around */
  846. void FFreeAll(void)
  847.     {
  848.     MemoryLinks *dump = THeadPtr->next, *nextOne;
  849.     
  850.     while (dump != THeadPtr)
  851.         {
  852.         nextOne = dump->next;
  853.         DisposPtr((Ptr)dump);
  854.         dump = nextOne;
  855.         }
  856.     }
  857.  
  858.  
  859. /* Misc */
  860.  
  861. void NullOut(char *str, long nBytes)
  862.     {
  863.     register long i;
  864.     
  865.     i = nBytes;
  866.     while (--i >= 0)
  867.         *str++ = '\0';
  868.     }
  869.  
  870. /* Check for the generic "Command<period>" that signals a
  871. wish to stop. */
  872. Boolean TaskWasInterrupted()
  873.     {
  874.     EventRecord    event;
  875.     long        thisTime;
  876.     Boolean        gotEvent;
  877.     static long    lastTime;
  878.     
  879.     Delay(0L, &thisTime);
  880.     if (thisTime - lastTime < 60L) return(FALSE);
  881.     lastTime = thisTime;
  882.     SystemTask();
  883.     gotEvent = GetNextEvent(62, &event);
  884.     if (gotEvent) /* see if interrupt */
  885.         {
  886.         switch (event.what)
  887.             {
  888.         case keyDown:
  889.         case autoKey:
  890.             /* look for abort key (Command-<period>) */
  891.         if ((event.modifiers & cmdKey)
  892.              && ((event.message & charCodeMask) == '.'))
  893.             {
  894.             return(TRUE);
  895.             }
  896.         break;
  897.         default:
  898.         break;
  899.             } /* switch */
  900.         }
  901.     return(FALSE);
  902.     }
  903.  
  904. /* Check for events 15 times a second, allow hAWK to run for
  905. at most 12 ticks if no event. Return control to calling
  906. app's event loop, so that hAWK can run at the same time
  907. as calling app without too much slowdown. Return TRUE
  908. if interrupted, FALSE if should continue. */
  909. Boolean CheckInWithCallingApp()
  910.     {
  911.     EventRecord    event;
  912.     long        thisTime;
  913.     Boolean        gotEvent;
  914.     static long    lastTime, tickAlong;
  915.     
  916.     Delay(0L, &thisTime);
  917.     if (thisTime < tickAlong) return(FALSE);
  918.     tickAlong = thisTime + 4L;
  919.     
  920.     if ((gotEvent = EventAvail(everyEvent, &event))
  921.         || thisTime - lastTime > 12L)
  922.         {
  923.         if (gotEvent)
  924.             {
  925.             switch (event.what)
  926.                 {
  927.             case keyDown:
  928.             case autoKey:
  929.                 /* look for abort key (Command-<period>) */
  930.             if ((event.modifiers & cmdKey)
  931.                  && ((event.message & charCodeMask) == '.'))
  932.                 {
  933.                 GetNextEvent(62, &event);
  934.                 return(TRUE);
  935.                 }
  936.             break;
  937.             default:
  938.             break;
  939.                 } /* switch */
  940.             }
  941.         else
  942.             lastTime = thisTime;
  943.         DoEventLoopOnce();
  944.         }
  945.     return(FALSE);
  946.     }
  947.